#pragma once
#include <gfx/vk/core.h>
#include <common_header.h>
#include <gfx/vk/helper.h>

namespace primal
{
	namespace gfx
	{
		struct FrameCommandData
		{
			VkCommandPool allocator;
			VkCommandBuffer list;
			VkFence fence;
			VkSemaphore signal_semaphore;
		};

		template<u64 FRAME_COUNT,u64 FC_1 = FRAME_COUNT - 1>
		class CommandBase
		{
		public:
			//static_assert((FRAME_COUNT& FC_1) == 0);
			CommandBase();
			~CommandBase();

			VkCommandBuffer begin();
			VkSemaphore end(VkSemaphore* semaphores, u32 count);
		private:
			FrameCommandData frames[FRAME_COUNT];
			u64 frame_index;
		};
		template<u64 FRAME_COUNT, u64 FC_1>
		inline CommandBase<FRAME_COUNT, FC_1>::CommandBase() :frames{}, frame_index{}
		{
			VkDeviceClass& vk_device{ primal::gfx::dev() };
			for(FrameCommandData& item : frames)
			{
				vkx::command_pool_create_info pool_info{};
				vk_device.CreateCommandPool(pool_info.init(default_queue_family_index, 0), &item.allocator);
				vkx::command_buffer_info buf_inf{};
				vk_device.AllocateCommandBuffers(buf_inf.init(item.allocator, 1u), &item.list);
				vk_device.CreateFence(&item.fence);
				vk_device.CreateSemaphore(&item.signal_semaphore);
			}
		}
		template<u64 FRAME_COUNT, u64 FC_1>
		inline CommandBase<FRAME_COUNT, FC_1>::~CommandBase()
		{}
		template<u64 FRAME_COUNT, u64 FC_1>
		inline VkCommandBuffer CommandBase<FRAME_COUNT, FC_1>::begin()
		{
			VkDeviceClass& vk_device{ primal::gfx::dev() };
			FrameCommandData& cur_frame{ frames[frame_index] };
			vk_device.WaitForFences(&cur_frame.fence);
			vk_device.ResetFences(&cur_frame.fence);
			vk_device.ResetCommandPool(cur_frame.allocator, 0);

			//vk_device.vkBeginCommandBuffer(cur_frame.list, &vkx::def.cmd_begin_info);
			return cur_frame.list;
		}
		template<u64 FRAME_COUNT, u64 FC_1>
		inline VkSemaphore CommandBase<FRAME_COUNT, FC_1>::end(VkSemaphore* semaphores, u32 count)
		{
			VkDeviceClass& vk_device{ primal::gfx::dev() };
			FrameCommandData& cur_frame{ frames[frame_index] };
			vk_device.vkEndCommandBuffer(cur_frame.list);

			VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
			VkSubmitInfo submitInfo{};
			submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
			submitInfo.waitSemaphoreCount = count;
			submitInfo.pWaitSemaphores = semaphores;
			submitInfo.pWaitDstStageMask = waitStages;
			submitInfo.commandBufferCount = 1;
			submitInfo.pCommandBuffers = &cur_frame.list;
			submitInfo.signalSemaphoreCount = 1;
			submitInfo.pSignalSemaphores = &cur_frame.signal_semaphore;

			vk_device.vkQueueSubmit(graphics_queue(), 1u, &submitInfo, cur_frame.fence);

			frame_index = (frame_index + 1ull) & FC_1;
			return cur_frame.signal_semaphore;
		}
	}
}